package net;

import java.beans.IntrospectionException;
import java.io.IOException;

import org.apache.commons.betwixt.strategy.SimpleTypeMapper;

/**
 * Encapsulates certain stream input and output capabilities, in particular the
 * ability to convert beans to XML and back.
 */
public abstract class ObjectSerializer
{
	/**
	 * Constructs a new <code>ObjectSerializer</code> connected to the given socket.
	 * @param socket
	 * @param reactorProxyClass
	 * @param nameMapper
	 * @throws IOException
	 */
	public ObjectSerializer(java.net.Socket socket, Class<? extends net.ReactorProxy<?>> reactorProxyClass, org.apache.commons.betwixt.strategy.NameMapper nameMapper) throws IOException
	{
		connection = new Connection(socket);
		reader = new org.apache.commons.betwixt.io.BeanReader();
		writer = new org.apache.commons.betwixt.io.BeanWriter(connection.out());

		// Here begins the black magic of betwixt configuration.
		// Abandon all hope, ye who enter here!
		writer.setWriteEmptyElements(false);

		writer.getXMLIntrospector().getConfiguration().setPropertySuppressionStrategy(new org.apache.commons.betwixt.strategy.PropertySuppressionStrategy() {
			public boolean suppressProperty(Class classContainingTheProperty, Class propertyType, String propertyName) {
				// don't suppress the 'class' property, so that derived beans will work
				if ("class".equals(propertyName))
					return false;
				try {
					// Suppress properties with no setters.
					for (java.beans.PropertyDescriptor p : java.beans.Introspector.getBeanInfo(classContainingTheProperty).getPropertyDescriptors())
						if (p.getName().equals(propertyName))
							return p.getWriteMethod() == null;
				} catch (IntrospectionException e) {
					e.printStackTrace();
				}
				return false;
			}
		});
		writer.getXMLIntrospector().getConfiguration().setSimpleTypeMapper(new SimpleTypeMapper() {
			public Binding bind(String propertyName, Class propertyType, org.apache.commons.betwixt.IntrospectionConfiguration arg2) {
				if (Class.class.equals(propertyType))
					return SimpleTypeMapper.Binding.ATTRIBUTE;
				return SimpleTypeMapper.Binding.ELEMENT;
			}
		});

		reader.getBindingConfiguration().setClassNameAttribute("class");
		writer.getXMLIntrospector().getConfiguration().setElementNameMapper(nameMapper);
		try {
			reader.registerBeanClass("session", reactorProxyClass);
		} catch (IntrospectionException e) {e.printStackTrace();}

		ObjectStoringStrategy idMapper = new ObjectStoringStrategy(dictionary);
		idMapper.setReference(null, this, "me");
		writer.getBindingConfiguration().setIdMappingStrategy(idMapper);
		idMapper = new ObjectStoringStrategy(dictionary);
		idMapper.setReference(null, this, "me");
		reader.getBindingConfiguration().setIdMappingStrategy(idMapper);

		connection.println("<?xml version='1.0' ?>");
		connection.println("<session>");
		connection.println("<reactor idref=\"me\"/>");
	}

	/**
	 * Write a JavaBean to our output stream. This will write out the bean and
	 * any get/set properties it contains, including other beans recursively.
	 * @param bean The bean to be written
	 * @throws IOException
	 */
	protected void writeBean(Object bean) throws IOException
	{
		try {
			writer.write(bean);
			writer.flush();
		} catch (org.xml.sax.SAXException e) {
			throw new IOException(e.getMessage());
		} catch (IntrospectionException e) {
			throw new IOException(e.getMessage());
		}
	}

	protected final core.Dictionary dictionary = new core.Dictionary();
	protected final Connection connection;
	protected final org.apache.commons.betwixt.io.BeanWriter writer;
	protected final org.apache.commons.betwixt.io.BeanReader reader;
}